﻿/*****************************************************************
 * @file sys.h
 * @author ShiHongChao
 * @brief here are globally-called functions, global hooks or weak functions,
 *        global configurations. and organize header file dependencies.
 *****************************************************************
 */

#ifndef __SYS_H__
#define __SYS_H__
#ifdef __cplusplus
extern "C" {
    #endif

    #include "gd32f10x.h"


    typedef void (*init_fn_t)(void);

    #define USED __attribute__((used))
    #define SECTION(x) __attribute__((section(x)))

    #if defined(DEBUG)
    typedef struct
    {
        const char *name;
        init_fn_t fn_addr;
    }init_desc;

    /* 定义输入段开始地址 */
    #define INIT_BSP_START() \
        USED const init_desc __init_start SECTION(".init_fn.0") = {0}
    /* 定义输入段结束地址 */
    #define INIT_BSP_END() \
        USED const init_desc __init_end SECTION(".init_fn.1.end") = {0}
    /* 导出到BSP自动初始化输入段 */
    #define INIT_BSP_EXPORT(fn) \
        USED const char __init_##fn##_name[] = #fn;  \
        USED const init_desc __init_##fn SECTION(".init_fn.1") = {.fn_addr = fn,\
            .name = __init_##fn##_name}

    extern const init_desc __init_start;
    extern const init_desc __init_end;
    #else
    /* 定义输入段开始地址 */
    #define INIT_BSP_START() \
        USED const init_fn_t __init_start SECTION(".init_fn.0") = 0
    /* 定义输入段结束地址 */
    #define INIT_BSP_END() \
        USED const init_fn_t __init_end SECTION(".init_fn.1.end") = 0
    /* 导出到BSP自动初始化输入段 */
    #define INIT_BSP_EXPORT(fn) \
        USED const init_fn_t __init_##fn SECTION(".init_fn.1") = fn

    extern const init_fn_t __init_start;
    extern const init_fn_t __init_end;
    #endif

    /* 声明为程序构造函数 先于main函数执行 自动调用 */
    #define CONSTRUCTOR(fn) void fn(void) __attribute__((constructor))

    /* 计算结构体成员地址偏移 */
    #define offsetof(type, member) ((uint32_t)(&((type *)0)->member))

    /* 从成员获取结构体指针 */
    #define objectof(member_ptr, type, member) \
        (type *)((char *)(member_ptr) - offsetof(type, member))


    /**
     * @defgroup 位带
     * @note 注意地址是否属于位带区
     * @{
     */
    #define BIT_BAND(addr, bit) ((((addr) & 0xF0000000)) + 0x02000000 + (((addr) & 0xFFFFF) << 5) + ((bit) << 2))
    #define BIT_ALIAS(addr, bit) (*(volatile uint32_t *)(BIT_BAND((addr), (bit))))
    /**
     * @} 位带
     */


    #ifdef __cplusplus
}
#endif
#endif // SYS_H
